package com.m1.tzolkin.model.buildables;

import java.util.Collection;

import com.m1.tzolkin.model.Action;
import com.m1.tzolkin.model.IAction;
import com.m1.tzolkin.model.ITZStock;
import com.m1.tzolkin.model.Season;
import com.m1.tzolkin.model.TZResource;
import com.m1.tzolkin.model.TZStock;
import com.m1.tzolkin.model.TzolkinConstants;
import com.m1.tzolkin.model.board.ITZBoard;
import com.m1.tzolkin.model.exceptions.NoAvailableSkullException;
import com.m1.tzolkin.model.exceptions.NotAvailableActionException;
import com.m1.tzolkin.model.exceptions.NotEnoughCornException;
import com.m1.tzolkin.model.players.ITZPlayer;
import com.m1.tzolkin.model.technos.ITechnology;
import com.m1.tzolkin.model.technos.ITechnology.TechLevel;
import com.m1.tzolkin.model.technos.Technologies;
import com.m1.tzolkin.model.temples.ITemple;
import com.m1.tzolkin.model.temples.TempleEnum;
import com.m1.tzolkin.model.wheels.WheelEnum;

public enum MonumentTypes implements TzolkinConstants {
	MONUMENT_1(BuildableType.FUNERAL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -2906378682048524447L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			int playersNb = b.getPlayers().size();
			for (ITZPlayer pl : b.getPlayers()) {
				addPoints += pl.getMonuments().size() * (MAX_PLAYERS - (playersNb - 2));
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 2)
			.addResource(TZResource.STONE, 2)
			.addResource(TZResource.GOLD, 2)
	),
	MONUMENT_2(BuildableType.SACRED, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 460479166679202243L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			for (IAction a : b.getWheel(WheelEnum.CHICHEN_ITZA).getActions()) {
				if (a.isAvailable()) {
					addPoints += 3;
				}
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.GOLD, 4)
			.addSkull(1)
	),
	MONUMENT_3(BuildableType.CIVIL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 8980725934448786685L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = b.getTechnologies(p).size() * 3;
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 2)
			.addResource(TZResource.STONE, 1)
			.addResource(TZResource.GOLD, 3)
	),
	MONUMENT_4(BuildableType.FUNERAL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -280270374757264238L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 4 * p.getCornTiles();
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 1)
			.addResource(TZResource.STONE, 1)
			.addResource(TZResource.GOLD, 4)
	),
	MONUMENT_5(BuildableType.SACRED, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -5056715780015486439L;

		public void doAction(ITZBoard b, ITZPlayer p) throws NoAvailableSkullException, NotEnoughCornException, NotAvailableActionException {
			int addPoints = (int) p.getScore();
			for (ITemple t : TempleEnum.values()) {
				t.getActions(Season.END_ERA)[b.getTemplePosition(t, p)].doAction(b, p);
			}
			addPoints = (int) p.getScore() - addPoints;
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.STONE, 4)
			.addResource(TZResource.GOLD, 3)
	),
	MONUMENT_6(BuildableType.CIVIL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 9187135029349334615L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			for (IActionBuilding building : p.getActionBuildings()) {
				if (building.getType().equals(BuildableType.CIVIL)) {
					addPoints += 4;
				}
			}
			for (IMonument m : p.getMonuments()) {
				if (m.getType().equals(BuildableType.CIVIL)) {
					addPoints += 4;
				}
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 2)
			.addResource(TZResource.STONE, 3)
			.addResource(TZResource.GOLD, 1)
	),
	MONUMENT_7(BuildableType.FUNERAL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -4789257594387973022L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			for (IActionBuilding building : p.getActionBuildings()) {
				if (building.getType().equals(BuildableType.FUNERAL)) {
					addPoints += 4;
				}
			}
			for (IMonument m : p.getMonuments()) {
				if (m.getType().equals(BuildableType.FUNERAL)) {
					addPoints += 4;
				}
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 3)
			.addResource(TZResource.STONE, 2)
			.addResource(TZResource.GOLD, 1)
	),
	MONUMENT_8(BuildableType.FUNERAL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -1968232930094826665L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			final int BONUS = 2;
			for (ITZPlayer pl : b.getPlayers()) {
				addPoints += BONUS * pl.getFarms().size();
				addPoints += BONUS * pl.getActionBuildings().size();
				addPoints += BONUS * pl.getMonuments().size();
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 1)
			.addResource(TZResource.STONE, 3)
			.addResource(TZResource.GOLD, 2)
	),
	MONUMENT_9(BuildableType.FUNERAL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 712263620933776641L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 4 * p.getWoodTiles();
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 1)
			.addResource(TZResource.GOLD, 4)
	),
	MONUMENT_10(BuildableType.CIVIL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -1891576252656972766L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			Collection<TechLevel> techs = b.getTechnologies(p);
			int tops = 0;
			for (ITechnology t : Technologies.values()) {
				if (techs.contains(t.getLevels()[t.getHeight() - 1])) {
					++tops;
				}
			}
			int addPoints = 0;
			switch(tops) {
			case 0: break;
			case 1: addPoints = 9; break;
			case 2: addPoints = 20; break;
			default: addPoints = 33;
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 1)
			.addResource(TZResource.STONE, 1)
			.addResource(TZResource.GOLD, 3)
	),
	MONUMENT_11(BuildableType.CIVIL, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -295755913083724278L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 6 * (p.getTotalPawns().size() - DEFAULT_WORKERS);
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.WOOD, 3)
			.addResource(TZResource.GOLD, 3)
	),
	MONUMENT_12(BuildableType.SACRED, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = -3759410803696268483L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			int maxPos = DEFAULT_TEMPLE_MARCH;
			for (ITemple t : TempleEnum.values()) {
				maxPos = Math.max(maxPos, b.getTemplePosition(t, p));
			}
			if (maxPos > DEFAULT_TEMPLE_MARCH) {
				addPoints = 3 * maxPos - DEFAULT_TEMPLE_MARCH;
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.STONE, 3)
			.addResource(TZResource.GOLD, 3)
	),
	MONUMENT_13(BuildableType.SACRED, new Action() {
		/**
		 * 
		 */
		private static final long serialVersionUID = 3075984809132739102L;

		public void doAction(ITZBoard b, ITZPlayer p) {
			int addPoints = 0;
			for (IActionBuilding building : p.getActionBuildings()) {
				if (building.getType().equals(BuildableType.SACRED)) {
					addPoints += 4;
				}
			}
			for (IMonument m : p.getMonuments()) {
				if (m.getType().equals(BuildableType.SACRED)) {
					addPoints += 4;
				}
			}
			p.addScore(addPoints);
			if (addPoints != 0) {
				b.getLog().addSentence(new String[] {
					p.getName(), "GET", "" + addPoints, "POINT" + (addPoints > 1 ? "S" : "")
				});
			}
		}
	}, new TZStock()
			.addResource(TZResource.STONE, 2)
			.addResource(TZResource.GOLD, 3)
	);
	
	// ATTRIBUTS
	
	private final BuildableType type;
	private final IAction action;
	private final ITZStock cost;
	
	// CONSTRUCTEUR
	
	private MonumentTypes(BuildableType type, IAction action, ITZStock cost) {
		this.type = type;
		this.action = action;
		this.cost = cost;
	}
	
	// REQUETES
	
	BuildableType getType() {
		return type;
	}
	
	IAction getAction() {
		return action;
	}
	
	ITZStock getCost() {
		return cost;
	}
	
}
